package jinyilw.swing.rlaf.ui;

import jinyilw.swing.ComponentTools;
import jinyilw.swing.FontTools;
import jinyilw.swing.graphics.RenderingConfig;
import jinyilw.swing.graphics.ShapeTools;
import jinyilw.swing.rlaf.theme.RThemeColor;

import javax.swing.ComboBoxEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicComboBoxUI;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * @author Jinyi
 */
public class RComboBoxUI extends BasicComboBoxUI
{
	static final int maxArrowSize = 22;
	protected boolean isRollover;
	protected int arc = 10;
	protected Shape triangle;
	protected int triangleSize;
	protected RenderingConfig renderingConfig = new RenderingConfig();

	public static ComponentUI createUI(JComponent c)
	{
		return new RComboBoxUI();
	}

	@Override
	public void installUI(final JComponent c)
	{
		super.installUI(c);
		c.setFont(FontTools.defaultFont);
		c.setOpaque(false);
		listBox.setOpaque(false);
		MouseListener mouseListener = new MouseAdapter()
		{
			@Override
			public void mouseExited(MouseEvent e)
			{
				if (c.isEnabled())
				{
					isRollover = false;
					c.repaint();
				}
			}
			@Override
			public void mouseEntered(MouseEvent e)
			{
				if (c.isEnabled())
				{
					isRollover = true;
					c.repaint();
				}
			}
		};

		c.addMouseListener(mouseListener);
	}

	@Override
	public void update(Graphics g, JComponent c)
	{
		Graphics2D g2d = (Graphics2D) g;
		Composite composite = ComponentTools.applyEnableAlpha(g2d, c, 0.92f,
				0.3f);
		if (editor == null)
		{
			Border border = c.getBorder();
			Insets insets = border != null
					? border.getBorderInsets(c)
					: new Insets(0, 0, 0, 0);
			int h = c.getHeight() - insets.top - insets.bottom;
			int w = c.getWidth() - insets.left - insets.right;
			renderingConfig.setAAPainting(g2d);
			g2d.setColor(RThemeColor.colorSet.transTBGColor);
			g2d.fillRoundRect(insets.left + 1, insets.top + 1, w - 2, h - 2,
					arc, arc);
			if (border == null)
			{
				g2d.setColor(isRollover
						? RThemeColor.themeColor
						: RThemeColor.colorSet.borderColor);
				g2d.drawRoundRect(1, 1, w - 2, h - 2, arc, arc);
			}
			if (triangle != null)
			{
				int x = w - triangleSize - 8 + insets.left;
				int y = (h - triangleSize) / 2 + insets.top + 1;
				g2d.setColor(isRollover
						? RThemeColor.themeColor
						: RThemeColor.colorSet.textColor);
				paintTriangle(g2d, x, y);
			}
			renderingConfig.resetAAPainting(g2d);
		}
		paint(g, c);
		if (composite != null)
			g2d.setComposite(composite);
	}

	protected void paintTriangle(Graphics2D g2d, int x, int y)
	{
		g2d.translate(x, y);
		// g2d.draw(triangle);
		g2d.fill(triangle);
		g2d.translate(-x, -y);
	}

	@Override
	public void paint(Graphics g, JComponent c)
	{
		hasFocus = comboBox.hasFocus();
		if (!comboBox.isEditable())
		{
			Rectangle r = rectangleForCurrentValue();
			paintCurrentValue(g, r, hasFocus);
		}
	}

	@Override
	public void paintCurrentValue(Graphics g, Rectangle bounds,
			boolean hasFocus)
	{
		ListCellRenderer<? super Object> renderer = comboBox.getRenderer();
		Component c;
		c = renderer.getListCellRendererComponent(listBox,
				comboBox.getSelectedItem(), -1, false, false);
		if (c instanceof JComponent)
			((JComponent) c).setOpaque(false);

		boolean shouldValidate = false;
		if (c instanceof JPanel)
			shouldValidate = true;

		int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height;
		if (padding != null)
		{
			x = bounds.x + padding.left;
			y = bounds.y + padding.top;
			w = bounds.width - (padding.left + padding.right);
			h = bounds.height - (padding.top + padding.bottom);
		}
		currentValuePane.paintComponent(g, c, null, x, y, w, h, shouldValidate);
	}

	@Override
	protected ListCellRenderer<Object> createRenderer()
	{
		return new RItemRenderer();
	}

	@Override
	protected ComboBoxEditor createEditor()
	{
		return new RComboBoxEditor();
	}

	@Override
	protected JButton createArrowButton()
	{
		return null;
	}

	@Override
	protected LayoutManager createLayoutManager()
	{
		return new RComboBoxLayout();
	}

	class RComboBoxLayout implements LayoutManager
	{
		@Override
		public void addLayoutComponent(String name, Component comp)
		{
		}

		@Override
		public void removeLayoutComponent(Component comp)
		{
		}

		@Override
		public Dimension preferredLayoutSize(Container parent)
		{
			return parent.getPreferredSize();
		}

		@Override
		public Dimension minimumLayoutSize(Container parent)
		{
			return parent.getMinimumSize();
		}

		@Override
		public void layoutContainer(Container parent)
		{
			JComboBox cb = (JComboBox) parent;
			Insets insets = getInsets();
			int width = cb.getWidth();
			int height = cb.getHeight() - (insets.top + insets.bottom);
			int buttonHeight = Math.min((int) (height * 0.8), maxArrowSize);
			int buttonWidth = buttonHeight;
			triangleSize = buttonHeight / 2;
			triangle = ShapeTools.createTriangle(SwingConstants.SOUTH,
					triangleSize, triangleSize);
			if (arrowButton != null)
			{
				Insets arrowInsets = arrowButton.getInsets();
				buttonWidth = squareButton
						? buttonHeight
						: arrowButton.getPreferredSize().width
						+ arrowInsets.left + arrowInsets.right;

				if (cb.getComponentOrientation().isLeftToRight())
				{
					arrowButton.setBounds(width - (insets.right + buttonWidth),
							(height - buttonHeight) / 2, buttonWidth,
							buttonHeight);
				} else
				{
					arrowButton.setBounds(insets.left,
							(height - buttonHeight) / 2, buttonWidth,
							buttonHeight);
				}
			}

			Rectangle cvb;
			if (editor != null)
			{
				cvb = rectangleForCurrentValue();
				editor.setBounds(cvb);
			}
		}
	}
}
